home *** CD-ROM | disk | FTP | other *** search
/ Megahits 5 / Megahits 5 (1994)(GTI - Rhein-Main-Soft)(DE)(Disc 2 of 2)[!].iso / archive / show / photocdaga10.lha / PhotoCDAGA / src / ppm2AGA / ppm2ilbm.c < prev    next >
C/C++ Source or Header  |  1994-11-20  |  30KB  |  976 lines

  1. /* ppm2ilbm module                 */
  2. /* written by Günther Röhrich      */
  3. /* this is version 1.5             */
  4.  
  5. /* this code is tested with Aztec C 5.2a and GNU C 2.5.8 */
  6. /* NOTE: you will need the newiff V37 or higher package */
  7. /* (V37 is available on Fish-disk 705) */
  8.  
  9.  
  10. #include <clib/exec_protos.h>
  11. #include <libraries/iffparse.h>
  12. #include <dos/dos.h>
  13. #include <iffp/ilbmapp.h>
  14. #include <iffp/packer.h>
  15. #include <stdio.h>
  16. #include <graphics/modeid.h>
  17.  
  18. #include "ppm2AGA.h"
  19.  
  20. #ifndef __GNUC__
  21. #include <pragmas/exec_pragmas.h>
  22. #include <pragmas/iffparse_pragmas.h>
  23. #endif
  24.  
  25.  
  26.  
  27. /* needed when compiling with newiff V37 package */
  28. /* (not needed with V39 or higher) */
  29.  
  30. #ifndef BMHDF_CMAPOK
  31. #define BMHDF_CMAPOK (1 << 7)
  32. #endif
  33.  
  34.  
  35. /* externals used by this module */
  36.  
  37.  
  38. extern int AbortCheck(void);
  39. extern void PLProgress(ULONG Value, ULONG MaxValue);
  40. extern volatile unsigned short MaxError, MaxErrorPos;
  41. extern void EncodeHAM(UBYTE *yorig, UBYTE *yham, char *ColorTable, 
  42.                        short NumColors, short xsize);
  43. extern int MapColorASM(colorhist_vector colormap, pixval r1, pixval g1, pixval b1, 
  44.              int NumColors);
  45. extern int ExactColor;
  46. extern int GfxEnable;
  47. extern int VGAenable;
  48. extern int jpegAGA;
  49. extern char *ILBMfile;
  50. extern char *BaseName;
  51. extern ULONG SMR;
  52. extern ULONG SMR_DisplayID;
  53.  
  54. /* definitions for the display routines */
  55.  
  56. extern int InitDisplay(int cols, int rows, ULONG Mode, int NumPlanes);
  57. extern void SetDisplayColor(int ColorNumber, UBYTE r, UBYTE g, UBYTE b);
  58. extern void DisplayRow(char *array, int cols, int row);
  59. extern void CloseDisplay(void);
  60.  
  61. /* globals defined in this module */
  62.  
  63. #ifdef DEBUG_ASM
  64. int MapColor(colorhist_vector colormap, pixval r1, pixval g1, pixval b1, 
  65.              int NumColors);
  66. #endif
  67.  
  68. unsigned short Mult_Table[2*256];
  69. unsigned long  Mult_Table32[2*256];
  70. jmp_buf ErrorEnv;
  71. int cols, rows, rowcnt;
  72. pixel **pixels;
  73. pixel *pixrow;
  74. pixval maxval;
  75. int ppmformat;
  76. char ColorTable[64*3] = {0};
  77. int ColorRegMax; 
  78. unsigned short ConvertMode;
  79. char *ColorCache; /* a 256K cache for EncodeHAM() */
  80.  
  81. /* these are needed by Floyd-Steinberg-routines */
  82. long  *thisrerr;
  83. long  *nextrerr;
  84. long  *thisgerr;
  85. long  *nextgerr;
  86. long  *thisberr; 
  87. long  *nextberr;     
  88. extern int floyd; 
  89. int fs_direction = 1;
  90. int Convert4096;
  91. int Convert262144;
  92. #define FS_SCALE 1024
  93.  
  94. /* locals defined in this module */
  95.  
  96. static FILE *fppm;
  97. static FILE *ColorMapFile;
  98. static struct IFFHandle *iff;
  99. static struct ILBMInfo ilbm;
  100. static int error;
  101. static LONG IFFError;
  102. static unsigned char *coded_rowbuf;
  103. static unsigned char *hamarray;
  104. static int returnvalue;
  105. static void ppmCleanUp(void);
  106. static int readall;
  107. static colorhist_vector chv, colormap;
  108. static BYTE *CompressBuffer;
  109. static void encode_row(UBYTE *row, int cols, int nPlanes);
  110. static int ColorShift, NumColors;
  111. static gray *pgmrow;
  112.  
  113. static int lumcompare(colorhist_vector ch1, colorhist_vector ch2)
  114. {
  115.  return (int)((double)PPM_LUMIN(ch1->color) - (double)PPM_LUMIN(ch2->color));
  116. }
  117.  
  118.  
  119. int ppm2ilbm(char *PPMfile, ULONG Mode, int NumPlanes, ULONG MaxMem)
  120. {
  121.  int i, colors;
  122.  pixel *pP;
  123.  unsigned short AbsMaxError = 0;
  124.  unsigned short MaxErrorXPos = 0;
  125.  unsigned short MaxErrorYPos = 0;
  126.  
  127.  /* initialize everything                            */
  128.  /* this is needed because we may call this function */
  129.  /* multiple times                                   */
  130.  returnvalue = 0;
  131.  fppm = NULL;
  132.  ColorMapFile = NULL;
  133.  readall = 0;
  134.  pixrow = NULL;
  135.  pixels = NULL;
  136.  hamarray = NULL; coded_rowbuf = NULL; ColorCache=NULL; 
  137.  memset(&ilbm, 0, sizeof(struct ILBMInfo)); 
  138.  chv = NULL;
  139.  colormap = NULL;
  140.  CompressBuffer = NULL;
  141.  pgmrow = NULL;
  142.  
  143.  
  144.  /* multiplication table is needed by assembler subroutines */
  145.  for(i=-255; i<256; i++)
  146.  {
  147.    Mult_Table[i+255] = i*i;
  148.    Mult_Table32[i+255] = i*i;
  149.  }
  150.  
  151.  
  152.  /* if we encounter an error we longjmp() to this location       */
  153.  /* the ppmCleanUp() function will free all resources  allocated */
  154.  /* in this module                                               */
  155.  
  156.  error = setjmp(ErrorEnv);
  157.  if(error != 0) 
  158.  {
  159.   ppmCleanUp();
  160.   return error;
  161.  }  
  162.  
  163.  
  164.  /* try to open the ppm file */
  165.  fppm = fopen(PPMfile, "r");
  166.  if(!fppm) pm_error("Could not open file %s\n", PPMfile);
  167.  
  168.  /* read the header of the ppm file */
  169.  ppm_readppminit(fppm, &cols, &rows, &maxval, &ppmformat); 
  170.  
  171.  #ifdef DEBUG
  172.  pm_message("Cols: %d, Rows: %d, MaxVal: %d, Format: %d\n",
  173.              cols, rows, maxval, ppmformat);
  174.  #else
  175.  pm_message("Cols: %d, Rows: %d, MaxVal: %d\n", cols, rows, maxval);
  176.  #endif
  177.  
  178.  /* Initialize Floyd-Steinberg error vectors. */
  179.  thisrerr = (long*) pm_allocrow( cols + 2, sizeof(long) );
  180.  nextrerr = (long*) pm_allocrow( cols + 2, sizeof(long) );
  181.  thisgerr = (long*) pm_allocrow( cols + 2, sizeof(long) );
  182.  nextgerr = (long*) pm_allocrow( cols + 2, sizeof(long) );
  183.  thisberr = (long*) pm_allocrow( cols + 2, sizeof(long) );
  184.  nextberr = (long*) pm_allocrow( cols + 2, sizeof(long) );
  185.  srandom( (int) ( time( 0 ) ^ getpid(0) ) );
  186.  for ( i = 0; i < cols + 2; ++i )
  187.  {
  188.    thisrerr[i] = random( ) % ( FS_SCALE * 2 ) - FS_SCALE;
  189.    thisgerr[i] = random( ) % ( FS_SCALE * 2 ) - FS_SCALE;
  190.    thisberr[i] = random( ) % ( FS_SCALE * 2 ) - FS_SCALE;
  191.    /* (random errors in [-1 .. 1]) */ 
  192.  }
  193.  
  194.  /* try to open the output file */
  195.  
  196.  if(!jpegAGA)
  197.  {
  198.    if(!(ilbm.ParseInfo.iff = AllocIFF()))
  199.      pm_error("Could not do AllocIFF()");
  200.  
  201.    iff = ilbm.ParseInfo.iff;
  202.  
  203.    IFFError = openifile((struct ParseInfo *)&ilbm, (UBYTE *)ILBMfile, IFFF_WRITE);
  204.    if(IFFError) pm_error(""); /* openifile() will print error messages... */
  205.  }
  206.  
  207.  if(Mode == HAM8 || Mode == HAM6 || Mode == COLORMAP)
  208.  {
  209.    int Clustering;
  210.    if(Mode == HAM8)
  211.    {
  212.      NumColors = NumPlanes;
  213.      ColorRegMax  = 63;
  214.      ColorShift   = 2; /* we only have 256K colors */
  215.      NumPlanes    = 8;
  216.      ConvertMode  = 1; /* Needed by EncodeHAM() */
  217.      Clustering   = 0;
  218.      Convert4096  = 0; /* No 4096-FS conversion */
  219.      if(floyd) Convert262144 = 1; /* 262144 conversion */
  220.     
  221.    }
  222.    else if(Mode == HAM6)
  223.    {
  224.      NumColors = NumPlanes;
  225.      ColorRegMax = 15; 
  226.      ColorShift  = 4; /* converting to 4096 colors will be done by FS dithering */
  227.      NumPlanes   = 6;
  228.      ConvertMode = 0; /* Needed by EncodeHAM() */
  229.      Clustering  = 0;
  230.      if(floyd)
  231.        Convert4096 = 1; /* Do 4096-FS conversion */
  232.      Convert262144 = 0;
  233.    }
  234.    else /* COLORMAP */
  235.    { 
  236.      NumColors = 1 << NumPlanes;      
  237.      ColorRegMax = 255;
  238.      ColorShift = 0; /* we will handle full 16M colors */
  239.      if(ppmformat == PGM_FORMAT || ppmformat == RPGM_FORMAT || ExactColor == 1)
  240.      {
  241.        Clustering = 0;
  242.      }
  243.      else
  244.      {
  245.        Clustering = 2;
  246.      }
  247.      Convert4096 = 0; /* No 4096-FS conversion */
  248.      Convert262144 = 0;
  249.    } 
  250.        
  251.    if( cols*rows*3 <= (int)MaxMem)
  252.    {     
  253.      /* read the complete picture into memory */
  254.      int row;
  255.      readall = 1;
  256.      pm_message("Reading complete picture into memory...\n");
  257.      pixels = ppm_allocarray(cols, rows);     
  258.      for(row = 0; row < rows; ++row)
  259.      {
  260.        if(AbortCheck()) pm_error("^C\n");
  261.        ppm_readppmrow(fppm, pixels[row], cols, maxval, ppmformat);
  262.        if(maxval != ColorRegMax)
  263.        {
  264.          if(maxval == 255)
  265.          {
  266.            for(i=0, pP=pixels[row]; i < cols; ++i, ++pP)
  267.            {
  268.              pP->r = pP->r >> ColorShift;
  269.              pP->g = pP->g >> ColorShift;
  270.              pP->b = pP->b >> ColorShift;
  271.            }
  272.          }
  273.          else
  274.          {
  275.            for(i=0, pP=pixels[row]; i < cols; ++i, ++pP)
  276.              PPM_DEPTH(*pP, *pP, maxval, ColorRegMax);
  277.          }
  278.        }
  279.      }
  280.    }
  281.    else
  282.    {
  283.      rowcnt = 0;
  284.      if(!(pixrow = ppm_allocrow(cols)))
  285.        pm_error("Out of memory.\n");     
  286.     }
  287.  
  288.  
  289.    /* allocate enough room for one row of chunky HAM pixels  */
  290.    /* (this array will also be used for colormap conversion) */
  291.    if(!(hamarray = malloc(RowBits(cols))))
  292.      pm_error("Out of memory.\n");
  293.  
  294.    /* we only have to clear the space between cols and RowBits(cols)    */
  295.    /* hamarray will be larger in most cases because of special alignment*/
  296.    for(i = cols; i < RowBits(cols); i++) hamarray[i] = 0;
  297.    pm_message("Computing colormap...\n");
  298.  
  299.  
  300.    /* now we make a histogram of the picture...          */
  301.    /* if we increase Clustering we will find less colors */
  302.    /* we allow a maximum of 10000 colors                 */
  303.    /* ColorShift is the shift needed for HAM encoding    */
  304.    for(i=Clustering; i<5; i++)
  305.    {
  306.      if((chv = ppm_fcomputecolorhist(fppm, cols, rows, 10000, &colors, ColorShift, i)))
  307.        break;
  308.      if(AbortCheck()) pm_error("^C\n");
  309.      pm_message("Could not compute colormap, trying again...\n");
  310.      rowcnt=0;
  311.      if(!readall)
  312.      { 
  313.        rewind(fppm); /* re-initialise the ppm pointers for reading again */
  314.        ppm_readppminit(fppm, &cols, &rows, &maxval, &ppmformat);       
  315.      }
  316.    } 
  317.  
  318.    pm_message("Found %d colors.\n", colors);
  319.  
  320.  
  321.    /* now we try to find a suitable colormap... */
  322.    colormap = mediancut(chv, colors, rows*cols, ColorRegMax, NumColors);
  323.    ppm_freecolorhist(chv); /* we don't need the histogram any more */
  324.    chv = NULL;
  325.    /* sort the colors in ascending luminance order...  */ 
  326.    /* (the first color will be the background color)      */
  327.    if(NumColors < colors)
  328.    {
  329.      qsort((char *)colormap, NumColors, sizeof(struct colorhist_item), lumcompare);
  330.    }
  331.    else
  332.    {
  333.      qsort((char *)colormap, colors, sizeof(struct colorhist_item), lumcompare);
  334.    }
  335.  
  336.    
  337.    if(!jpegAGA)
  338.    {   
  339.      /* the CompressBuffer is needed by the cmpByteRun1 compressor */
  340.      if(!(CompressBuffer = malloc(MaxPackedSize(RowBytes(cols)))))
  341.        pm_error("Out of memory allocating the compress buffer.\n");
  342.  
  343.      /* the ColorCache is needed by EncodeHAM() for higher speed */
  344.      /* (for HAM6 encoding only 4097 bytes are needed...)        */
  345.      if(!(ColorCache = malloc(262145)))
  346.        pm_error("Out of memory allocating the color cache.\n");
  347.  
  348.      /* the coded_rowbuf is needed by the IFF encoder */
  349.      if(!(coded_rowbuf = (unsigned char *)malloc(RowBytes(cols))))
  350.        pm_error("Out of memory allocating coded_rowbuf.\n");
  351.      for(i=RowBytes(cols)-1; i>=0; i--) coded_rowbuf[i]=0;
  352.  
  353.      /* write the FORM chunk */
  354.      IFFError = PushChunk(iff, ID_ILBM, ID_FORM, IFFSIZE_UNKNOWN);
  355.      if(IFFError) pm_error("Error writing FORM chunk.\n");
  356.      
  357.      /* initialize the BMHD chunk */
  358.      ilbm.Bmhd.w = cols;
  359.      ilbm.Bmhd.h = rows;             /* Width, height in pixels */
  360.      ilbm.Bmhd.x = 0;
  361.      ilbm.Bmhd.y = 0;                /* x, y position for this bitmap  */
  362.      ilbm.Bmhd.nPlanes = NumPlanes;  /* # of planes (not including mask) */
  363.      ilbm.Bmhd.masking = mskNone;   
  364.      ilbm.Bmhd.compression = cmpByteRun1;   
  365.      ilbm.Bmhd.flags = BMHDF_CMAPOK;        /* CMAP has 8 significant bits */
  366.      ilbm.Bmhd.transparentColor = 0; 
  367.      ilbm.Bmhd.xAspect = cols;         
  368.      ilbm.Bmhd.yAspect = rows;       /* xAspect, yAspect */
  369.      ilbm.Bmhd.pageWidth = cols;
  370.      ilbm.Bmhd.pageHeight = rows;    /* pageWidth, pageHeight */
  371.   
  372.      /* write the BMHD chunk */   
  373.      IFFError = putbmhd(iff, &ilbm.Bmhd);
  374.      if(IFFError) pm_error("Error writing BMHD chunk.\n");
  375.   
  376.      if(GfxEnable) InitDisplay(cols, rows, Mode, NumPlanes);
  377.    }
  378.    
  379.    if(Mode == HAM8 || Mode == HAM6)
  380.    { 
  381.      /* fill in the ColorTable in B R G order */
  382.      /* (this is better for HAM encoding)     */       
  383.      for(i=0; i<NumColors; i++)
  384.      {
  385.        ColorTable[i*3]   = PPM_GETB(colormap[i].color);
  386.        ColorTable[i*3+1] = PPM_GETR(colormap[i].color);
  387.        ColorTable[i*3+2] = PPM_GETG(colormap[i].color);
  388.        if(!jpegAGA)
  389.          SetDisplayColor(i, PPM_GETR(colormap[i].color) << ColorShift,
  390.                             PPM_GETG(colormap[i].color) << ColorShift,
  391.                             PPM_GETB(colormap[i].color) << ColorShift);
  392.      }
  393.      free(colormap); /* we don't need the colormap any more */
  394.      colormap = NULL;
  395.  
  396.      if(jpegAGA)
  397.      {
  398.        char *MapDir;
  399.        unsigned short MagicNumber = 0x1203; /* guess what this means! */
  400.        int Reserved=0; 
  401.        unsigned char color;
  402.        MapDir = getenv("MAPDIR");  
  403.  
  404.        ColorMapFile = fopen(ILBMfile, "w");
  405.        
  406.        if(!ColorMapFile && !BaseName)
  407.        {
  408.          if(MapDir)
  409.           if(strlen(MapDir) != 0)
  410.          {
  411.            char *MapDirName;
  412.            int pos,i;
  413.            MapDirName = malloc(strlen(MapDir)+strlen(ILBMfile)+5); /* worst case */
  414.            if(!MapDirName) pm_error("Out of memory.\n");
  415.            strcpy(MapDirName, MapDir);
  416.  
  417.            i = strlen(MapDirName);
  418.            if(MapDirName[i-1] != '/' && MapDirName[i-1] != ':')
  419.            {
  420.              strcat(MapDirName, "/");
  421.              i++;
  422.            }
  423.            i = strlen(ILBMfile);
  424.            while(i > 0 && ILBMfile[i-1] != '/' && ILBMfile[i-1] != ':') i--;
  425.            strcat(MapDirName, &ILBMfile[i]);
  426.            ColorMapFile = fopen(MapDirName, "w");
  427.            if(ColorMapFile) pm_message("Writing mapfile: %s\n", MapDirName);
  428.          }
  429.        }
  430.        else if(!ColorMapFile && BaseName && MapDir)
  431.          if(strlen(MapDir) != 0)
  432.        {
  433.          char *NewName;
  434.          int i;
  435.          NewName = malloc(strlen(MapDir)+strlen(BaseName)+strlen(ILBMfile)); /* worst case */
  436.          if(!NewName) pm_error("Out of memory.\n");
  437.          strcpy(NewName, MapDir);
  438.          i=strlen(NewName);
  439.          if(NewName[i-1] != '/' && NewName[i-1] != ':')
  440.          {
  441.            strcat(NewName, "/");
  442.            i++;
  443.          }
  444.          strcat(NewName, BaseName);
  445.          i=strlen(ILBMfile);
  446.          while(i > 0 && ILBMfile[i-1] != '/' && ILBMfile[i-1] != ':') i--;
  447.          if(strlen(ILBMfile) > i+3)
  448.          {
  449.            strcat(NewName, &ILBMfile[i+3]);
  450.            i = strlen(NewName) - 4;
  451.            if(i < 1) pm_error("Wrong mapfile name.\n");
  452.            while(i > 0 && NewName[i-1] != '.') i--;
  453.            if(NewName[i-1] == '.')
  454.            {
  455.              strcpy(&NewName[i], "map");
  456.              printf("%s\n", NewName);
  457.              ColorMapFile = fopen(NewName, "w");
  458.            }
  459.          }
  460.          free(NewName);
  461.        }
  462.          
  463.  
  464.        if(!ColorMapFile) pm_error("Could not open color map file for jpegAGA.\n");
  465.  
  466.        if(fwrite(&MagicNumber, 2, 1, ColorMapFile) != 1) pm_error("Write error.\n");
  467.        if(fwrite(&Reserved,    4, 1, ColorMapFile) != 1) pm_error("Write error.\n");     
  468.        if(fwrite(ColorTable,  64*3, 1, ColorMapFile) != 1) pm_error("Write error.\n");
  469.        pm_message("Colormap file for jpegAGA/PhotoCDAGA created.\n");
  470.        ppmCleanUp();
  471.        return 0;
  472.      }
  473.  
  474.      memset(ColorCache, 0, 262145); /* clear the color cache */          
  475.  
  476.      do
  477.      {
  478.        int y;
  479.        rowcnt=0;
  480.        
  481.        /* if we don't need an additional color the color cache */
  482.        /* will remain valid and should not be cleared          */
  483.  
  484.        memset(ColorCache, 0, 262145); /* clear the color cache */
  485.    
  486.  
  487.        if(!readall)
  488.        {
  489.          rewind(fppm);
  490.          ppm_readppminit(fppm, &cols, &rows, &maxval, &ppmformat);
  491.        }
  492.  
  493.        /* if we have all colors we can write the CMAP chunk */
  494.        if(NumColors == ColorRegMax+1)
  495.        {
  496.          IFFError = PushChunk(iff, 0, ID_CMAP, (ColorRegMax+1)*3);
  497.          if(IFFError) pm_error("Error writing CMAP header.\n");
  498.  
  499.          for( i = 0; i <= ColorRegMax; i++) 
  500.          {
  501.            ColorRegister cmapReg;
  502.            cmapReg.red   = ColorTable[i*3+1] << ColorShift;   /* red */
  503.            cmapReg.green = ColorTable[i*3+2] << ColorShift;   /* green */
  504.            cmapReg.blue  = ColorTable[i*3]   << ColorShift;   /* blue */
  505.            IFFError = WriteChunkBytes(iff, (UBYTE *)&cmapReg, 3);
  506.            if(IFFError!=3) pm_error("Error writing CMAP chunk.\n");
  507.          }
  508.          IFFError = PopChunk(iff); /* close CMAP */
  509.          if(IFFError) pm_error("Error closing CMAP.\n");
  510.  
  511.          /* write the CAMG chunk */
  512.          if(SMR)
  513.          {
  514.            ilbm.camg = SMR_DisplayID;
  515.          }
  516.          else
  517.          {
  518.            if(VGAenable)
  519.            {
  520.              if(cols > 370 || rows > 260)
  521.              {
  522.                ilbm.camg = VGAPRODUCTHAM_KEY;
  523.              }
  524.              else
  525.              {
  526.                ilbm.camg = VGALORESHAMDBL_KEY;
  527.              }
  528.            }
  529.            else
  530.            {
  531.              ilbm.camg = HAM;
  532.              if(cols > 370) ilbm.camg = ilbm.camg | HIRES;
  533.              if(rows > 280) ilbm.camg = ilbm.camg | LACE;
  534.            }
  535.          }
  536.          IFFError = putcamg(iff, &ilbm.camg);
  537.          if(IFFError) pm_error("Error writing CAMG chunk.\n");
  538.  
  539.          /* start with the BODY chunk */
  540.          IFFError = PushChunk(iff, 0, ID_BODY, IFFSIZE_UNKNOWN);
  541.          if(IFFError) pm_error("Error writing BODY header.\n");
  542.        }
  543.  
  544.        /* set a dummy value for AbsMaxError                          */
  545.        /* it will contain the maximum error for the complete picture */ 
  546.        AbsMaxError=0;
  547.   
  548.        for(y=0; y<rows; y++)
  549.        {
  550.          pixel *nextrow;          
  551.  
  552.          MaxError = 0;         
  553.            
  554.          nextrow = next_pixrow(fppm, y, ColorShift);
  555.           
  556.          if(AbortCheck()) pm_error("^C\n");
  557.  
  558.          EncodeHAM(nextrow, hamarray, ColorTable, NumColors*3, (short)cols);
  559.  
  560.          
  561.          /* remember the color of the pixel with the maximum error */
  562.          /* even if MaxError == 0 we will get a valid entry in the */
  563.          /* colormap but it will not be used by the picture        */           
  564.          if(MaxError > AbsMaxError)
  565.          {
  566.            MaxErrorXPos = MaxErrorPos;
  567.            MaxErrorYPos = y;
  568.            AbsMaxError = MaxError;
  569.  
  570.            /* use the color of the pixel with the maximum error as */
  571.            /* a ColorTable entry                                   */
  572.            /* we will have to recompute the picture if we want to  */
  573.            /* use the additional color                             */
  574.            if(NumColors <= ColorRegMax)
  575.            {
  576.              ColorTable[NumColors*3]   = PPM_GETB(pixrow[MaxErrorXPos]);
  577.              ColorTable[NumColors*3+1] = PPM_GETR(pixrow[MaxErrorXPos]);
  578.              ColorTable[NumColors*3+2] = PPM_GETG(pixrow[MaxErrorXPos]);
  579.            }        
  580.          }
  581.  
  582.          /* if all colors are set we can write our row to the BODY chunk */
  583.          if(NumColors == ColorRegMax+1) 
  584.          {
  585.            encode_row(hamarray, cols, NumPlanes);
  586.          }
  587.          DisplayRow(hamarray, cols, y);
  588.        }
  589.  
  590.        /* this is only for debugging purposes */
  591.        if(NumColors <= ColorRegMax)
  592.        {
  593.          #ifdef DEBUG
  594.          pm_message("Max Error: %hd ", AbsMaxError);
  595.          #endif
  596.          if(AbsMaxError == 0)
  597.          {
  598.            printf("\n");
  599.          }
  600.          else
  601.          {
  602.            #ifdef DEBUG
  603.            pm_message("Color %hd, XPos: %hd, YPos: %hd\n", NumColors, MaxErrorXPos, MaxErrorYPos);
  604.            #endif
  605.          }
  606.        }
  607.        SetDisplayColor(NumColors, ColorTable[NumColors*3+1] << ColorShift,
  608.                                   ColorTable[NumColors*3+2] << ColorShift,
  609.                                   ColorTable[NumColors*3]   << ColorShift);
  610.        NumColors = NumColors + 1; 
  611.     
  612.      /* finish if we have set all colors */
  613.      } while(NumColors <= ColorRegMax+1);
  614.  
  615.  
  616.      #ifdef DEBUG
  617.      pm_message("Max Error: %hd, XOffset: %hd YOffset: %hd\n",
  618.                AbsMaxError, MaxErrorXPos, MaxErrorYPos);
  619.  
  620.      pm_message("Colortable: ");
  621.      for(i=0; i<=ColorRegMax; i++)
  622.      {
  623.        pm_message("%hd,%hd,%hd ",ColorTable[i*3],
  624.                    ColorTable[i*3+1],ColorTable[i*3+2]);
  625.      }
  626.      pm_message("\n");
  627.      #endif
  628.  
  629.      /* close the BODY chunk */
  630.      IFFError = PopChunk(iff); 
  631.      if(IFFError) pm_message("Error closing the BODY chunk.\n");
  632.    }
  633.    
  634.  
  635.    else if(Mode == COLORMAP)
  636.    { 
  637.      /* if floyd is nonzero we will use Floyd-Steinberg dithering */
  638.      int row, fs_direction;
  639.      register int col, limitcol, ind;
  640.      register pixel *pP;
  641.      register long sg, sr, sb, err;
  642.      long *temperr;
  643.  
  644.      /*
  645.      ** map the colors in the image to their closest match in the
  646.      ** new colormap, and write 'em out.
  647.      */
  648.        
  649.      pm_message( "Mapping image to new colors...\n" );
  650.  
  651.      /* write the CMAP chunk */
  652.      IFFError = PushChunk(iff, 0, ID_CMAP, NumColors*3);
  653.      if(IFFError) pm_error("Error writing CMAP header.\n");
  654.      for( i = 0; i < NumColors; i++) 
  655.      {
  656.        ColorRegister cmapReg;
  657.        cmapReg.red   = PPM_GETR( colormap[i].color );   /* red   */
  658.        cmapReg.green = PPM_GETG( colormap[i].color );   /* green */
  659.        cmapReg.blue  = PPM_GETB( colormap[i].color );   /* blue  */
  660.        SetDisplayColor(i, cmapReg.red, cmapReg.green, cmapReg.blue);
  661.        IFFError = WriteChunkBytes(iff, (UBYTE *)&cmapReg, 3);
  662.        if(IFFError!=3) pm_error("Error writing CMAP chunk.\n");
  663.      }
  664.      IFFError = PopChunk(iff); /* close CMAP */
  665.      if(IFFError) pm_error("Error closing CMAP.\n");
  666.  
  667.      /* write the CAMG chunk */
  668.      if(SMR)
  669.      {
  670.        ilbm.camg = SMR_DisplayID;
  671.      }
  672.      else
  673.      {
  674.        ilbm.camg = 0;
  675.        if(VGAenable)
  676.        {
  677.          if(cols > 370 || rows > 260)
  678.            ilbm.camg = VGAPRODUCT_KEY;
  679.          else
  680.            ilbm.camg = VGALORESDBL_KEY;
  681.        }
  682.        else
  683.        {
  684.          if(cols > 370) ilbm.camg = ilbm.camg | HIRES;
  685.          if(rows > 280) ilbm.camg = ilbm.camg | LACE;
  686.        }
  687.      }
  688.      IFFError = putcamg(iff, &ilbm.camg);
  689.      if(IFFError) pm_error("Error writing CAMG chunk.\n");
  690.  
  691.      /* start with the BODY chunk */
  692.      IFFError = PushChunk(iff, 0, ID_BODY, IFFSIZE_UNKNOWN);
  693.      if(IFFError) pm_error("Error writing BODY header.\n");
  694.  
  695.      rowcnt=0;
  696.      if(!readall)
  697.      {
  698.        rewind(fppm);
  699.        ppm_readppminit(fppm, &cols, &rows, &maxval, &ppmformat);       
  700.      }
  701.  
  702.      if ( floyd )
  703.      {
  704.        fs_direction = 1;
  705.      }
  706.      for ( row = 0; row < rows; ++row )
  707.      {
  708.        /* PLProgress(row, rows); */
  709.        if(AbortCheck()) pm_error("^C\n");
  710.        if ( floyd )
  711.          for ( col = 0; col < cols + 2; ++col )
  712.            nextrerr[col] = nextgerr[col] = nextberr[col] = 0;
  713.        if ( ( ! floyd ) || fs_direction )
  714.        {
  715.          col = 0;
  716.          limitcol = cols;
  717.          /* pP = pixels[row]; */
  718.          pP = next_pixrow(fppm, row, ColorShift);
  719.        }
  720.        else
  721.        {
  722.          col = cols - 1;
  723.          limitcol = -1;
  724.          /* pP = &(pixels[row][col]); */
  725.          pP = &(next_pixrow(fppm, row, ColorShift)[col]);
  726.        }
  727.        do
  728.        {
  729.          if ( floyd )
  730.          {
  731.            /* Use Floyd-Steinberg errors to adjust actual color. */
  732.            sr = PPM_GETR(*pP) + thisrerr[col + 1] / FS_SCALE;
  733.            sg = PPM_GETG(*pP) + thisgerr[col + 1] / FS_SCALE;
  734.            sb = PPM_GETB(*pP) + thisberr[col + 1] / FS_SCALE;
  735.            if ( sr < 0 ) sr = 0;
  736.            else if ( sr > maxval ) sr = maxval;
  737.            if ( sg < 0 ) sg = 0;
  738.            else if ( sg > maxval ) sg = maxval;
  739.            if ( sb < 0 ) sb = 0;
  740.            else if ( sb > maxval ) sb = maxval;
  741.            PPM_ASSIGN( *pP, sr, sg, sb );
  742.          }
  743.  
  744.          /* use the assembler subroutine for the colormap search */
  745.          /* this will consume most of the CPU time               */                     
  746.          ind = MapColorASM(colormap, PPM_GETR(*pP), PPM_GETG(*pP), PPM_GETB(*pP),
  747.                            NumColors);
  748.            
  749.          /* compare the results of the ASM versus the C routine */
  750.          /* if they differ the ASM routine has a bug...         */
  751.          /* (we don't need them because they are the same now)  */
  752.          #ifdef DEBUG_ASM
  753.          if(ind != MapColor(colormap, PPM_GETR(*pP), PPM_GETG(*pP), PPM_GETB(*pP),
  754.                             NumColors))
  755.            pm_message("Diff: row %d col %d  r %d g %d b %d\n", row,col,
  756.                        (int)PPM_GETR(*pP), (int)PPM_GETG(*pP), (int)PPM_GETB(*pP));
  757.          #endif
  758.  
  759.          if ( floyd )
  760.          {
  761.            /* Propagate Floyd-Steinberg error terms. */
  762.            if ( fs_direction )
  763.            {
  764.              err = ( sr - (long) PPM_GETR( colormap[ind].color ) ) * FS_SCALE;
  765.              thisrerr[col + 2] += ( err * 7 ) / 16;
  766.              nextrerr[col    ] += ( err * 3 ) / 16;
  767.              nextrerr[col + 1] += ( err * 5 ) / 16;
  768.              nextrerr[col + 2] += ( err     ) / 16;
  769.              err = ( sg - (long) PPM_GETG( colormap[ind].color ) ) * FS_SCALE;
  770.              thisgerr[col + 2] += ( err * 7 ) / 16;
  771.              nextgerr[col    ] += ( err * 3 ) / 16;
  772.              nextgerr[col + 1] += ( err * 5 ) / 16;
  773.              nextgerr[col + 2] += ( err     ) / 16;
  774.              err = ( sb - (long) PPM_GETB( colormap[ind].color ) ) * FS_SCALE;
  775.              thisberr[col + 2] += ( err * 7 ) / 16;
  776.              nextberr[col    ] += ( err * 3 ) / 16;
  777.              nextberr[col + 1] += ( err * 5 ) / 16;
  778.              nextberr[col + 2] += ( err     ) / 16;
  779.            }
  780.            else
  781.            {
  782.              err = ( sr - (long) PPM_GETR( colormap[ind].color ) ) * FS_SCALE;
  783.              thisrerr[col    ] += ( err * 7 ) / 16;
  784.              nextrerr[col + 2] += ( err * 3 ) / 16;
  785.              nextrerr[col + 1] += ( err * 5 ) / 16;
  786.              nextrerr[col    ] += ( err     ) / 16;
  787.              err = ( sg - (long) PPM_GETG( colormap[ind].color ) ) * FS_SCALE;
  788.              thisgerr[col    ] += ( err * 7 ) / 16;
  789.              nextgerr[col + 2] += ( err * 3 ) / 16;
  790.              nextgerr[col + 1] += ( err * 5 ) / 16;
  791.              nextgerr[col    ] += ( err     ) / 16;
  792.              err = ( sb - (long) PPM_GETB( colormap[ind].color ) ) * FS_SCALE;
  793.              thisberr[col    ] += ( err * 7 ) / 16;
  794.              nextberr[col + 2] += ( err * 3 ) / 16;
  795.              nextberr[col + 1] += ( err * 5 ) / 16;
  796.              nextberr[col    ] += ( err     ) / 16;
  797.            }
  798.          }
  799.  
  800.          /* *pP = colormap[ind].color; */
  801.          hamarray[col] = (unsigned char)ind;
  802.  
  803.          if ( ( ! floyd ) || fs_direction )
  804.          {
  805.            ++col;
  806.            ++pP;
  807.          }
  808.          else
  809.          {
  810.            --col;
  811.            --pP;
  812.          }
  813.        }
  814.        while ( col != limitcol );
  815.  
  816.        if ( floyd )
  817.        {
  818.          temperr = thisrerr;
  819.          thisrerr = nextrerr;
  820.          nextrerr = temperr;
  821.          temperr = thisgerr;
  822.          thisgerr = nextgerr;
  823.          nextgerr = temperr;
  824.          temperr = thisberr;
  825.          thisberr = nextberr;
  826.          nextberr = temperr;
  827.          fs_direction = ! fs_direction;
  828.        }
  829.  
  830.        /* ppm_writeppmrow( stdout, pixels[row], cols, maxval, 0 ); */
  831.        /* write one row to the BODY chunk */
  832.        encode_row(hamarray, cols, NumPlanes);
  833.        DisplayRow(hamarray, cols, row);
  834.      }
  835.      IFFError = PopChunk(iff); /* close the BODY */
  836.      if(IFFError) pm_error("Error closing the BODY chunk.\n");
  837.    }       
  838.  }
  839.  
  840.  closeifile((struct ParseInfo *)&ilbm);
  841.  ppmCleanUp();
  842.  return 0;
  843. }
  844.  
  845.  
  846. /* free all resources used by this module */
  847. void ppmCleanUp(void)
  848. {
  849.  CloseDisplay();
  850.  if(colormap) free(colormap);
  851.  if(pgmrow) pgm_freerow(pgmrow); 
  852.  if(coded_rowbuf) free(coded_rowbuf);
  853.  if(CompressBuffer) free(CompressBuffer);
  854.  if(ColorCache) free(ColorCache);
  855.  if(chv) free(chv);
  856.  if(hamarray) free(hamarray);
  857.  if(pixels)
  858.  {
  859.    ppm_freearray(pixels, rows);
  860.  } 
  861.  else
  862.  {
  863.    if(pixrow) pbm_freerow(pixrow);
  864.  }
  865.  if(fppm) fclose(fppm);
  866.  
  867.  if(jpegAGA)
  868.  {
  869.    if(ColorMapFile)
  870.    {
  871.      fclose(ColorMapFile);
  872.      ColorMapFile = NULL;
  873.    }
  874.  }
  875.  else
  876.  {
  877.    if(ilbm.ParseInfo.opened)
  878.    {
  879.      closeifile((struct ParseInfo *)&ilbm);
  880.      remove(ILBMfile);
  881.    }
  882.    if(ilbm.ParseInfo.iff) FreeIFF(ilbm.ParseInfo.iff);
  883.  }
  884. }
  885.  
  886.  
  887.  
  888. /* convert one row from chunky to planar, compress it, */
  889. /* and write it to the BODY chunk                      */
  890.  
  891. /* encode algorithm by Johan Widen (jw@jwdata.se) */
  892. /* modified by Günther Röhrich */
  893.  
  894. const unsigned char bit_mask[] = {1, 2, 4, 8, 16, 32, 64, 128};
  895.  
  896. static void
  897. encode_row(UBYTE *row, int cols, int nPlanes)
  898. {
  899.  register int plane, col;
  900.  int bytes;
  901.  LONG packedRowBytes;
  902.  BYTE *source;
  903.  BYTE *destination;
  904.  
  905.  bytes = RowBytes(cols);
  906.  
  907.  /* Encode and write raw bytes in plane-interleaved form. */
  908.  for( plane = 0; plane < nPlanes; plane++ ) 
  909.  {
  910.    int mask, cbit, wr;
  911.    unsigned char *cp;
  912.    UBYTE *rp;
  913.  
  914.    mask = 1 << plane;
  915.    cbit = -1;
  916.    cp = coded_rowbuf-1;
  917.    rp = row;
  918.    for( col = 0; col < cols; col++, cbit--, rp++ ) 
  919.    {
  920.      if( cbit < 0 ) 
  921.      {
  922.        cbit = 7;
  923.        *++cp = 0;
  924.      }
  925.      if( *rp & mask )
  926.        *cp |= bit_mask[cbit];
  927.    }
  928.    /* wr = fwrite(coded_rowbuf, 1, bytes, stdout); */
  929.  
  930.    /* compress the row */
  931.    source = coded_rowbuf;
  932.    destination = CompressBuffer;
  933.    packedRowBytes = packrow(&source, &destination, bytes);
  934.  
  935.    /* write the compressed row to the BODY chunk */  
  936.    IFFError = WriteChunkBytes(iff, CompressBuffer, packedRowBytes); 
  937.    if(IFFError!=packedRowBytes) pm_error("Error writing BODY chunk.\n");
  938.  }
  939. }
  940.  
  941.  
  942. #ifdef DEBUG_ASM
  943. /* this is the C version of the colormap search routine */
  944. /* (it is now replaced by the ASM version)              */
  945.  
  946. /* search colormap for closest match. */
  947. int MapColor(colorhist_vector colormap, pixval r, pixval g, pixval b, 
  948.              int newcolors)
  949.  int ind;
  950.  register int i, r1, g1, b1, r2, g2, b2;
  951.  register long dist, newdist;
  952.  r1 = r;
  953.  g1 = g;
  954.  b1 = b;
  955.  dist = 2000000000;
  956.  for ( i = 0; i < newcolors; ++i )
  957.  {
  958.    r2 = PPM_GETR( colormap[i].color );
  959.    g2 = PPM_GETG( colormap[i].color );
  960.    b2 = PPM_GETB( colormap[i].color );
  961.    newdist = ( r1 - r2 ) * ( r1 - r2 ) +
  962.              ( g1 - g2 ) * ( g1 - g2 ) +
  963.              ( b1 - b2 ) * ( b1 - b2 );
  964.    if ( newdist < dist )
  965.    {
  966.      ind = i;
  967.      dist = newdist;
  968.    }
  969.  }
  970.  return ind;
  971. }
  972. #endif
  973.  
  974.  
  975.